<?php

namespace Gaolei\WechatPay\lib;

/**
 * Class Pay 微信支付
 * @package common\services\payment\wechat
 * @author: gaolei 2021/4/24 11:02 上午
 *
 * @protected  string $appId 公众号 appID https://pay.weixin.qq.com 产品中心-开发配置-商户号
 * @protected string $mchId 商户号 mchID 微信支付商户号
 * @protected string $apiKey 商户号接口秘钥 帐户设置-安全设置-API安全-API密钥-设置API密钥
 */
abstract class Wechat
{

    protected $appId;
    protected $mchId;
    protected $apiKey;

    /**
     * 获取实例化
     * @param array $payConfig
     * @return static
     * @author: gaolei 2021/4/27 3:30 下午
     */
    public static function create(array $payConfig)
    {
        $instance = new static();
        $instance->appId = $payConfig['appId'];
        $instance->mchId = $payConfig['mchId'];
        $instance->apiKey = $payConfig['apiKey'];
        return $instance;
    }

    /**
     * 获取随机字符串
     * @param int $length
     * @return string
     * @throws \Exception
     * @author: gaolei 2021/4/24 10:43 上午
     */
    protected function createNonceStr(int $length = 16): string
    {
        $baseStr = 'aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ1234567890';
        $code = '';
        $strLen = strlen($baseStr) - 1;
        for ($i = 0; $i < $length; $i++) {
            $code .= substr($baseStr, rand(0, $strLen), 1);
        }
        return $code;
    }


    /**
     * 计算签名
     * @param array $params
     * @param string $key
     * @return string
     * @author: gaolei 2021/4/24 10:42 上午
     */
    protected function getSign(array $params, string $key): string
    {
        ksort($params, SORT_STRING);
        $sign = '';
        foreach ($params as $k => $v) {
            if (null !== $v && "null" !== $v) {
                $sign .= $k . "=" . $v . "&";
            }
        }
        if (!empty($sign)) {
            $sign = substr($sign, 0, -1);
        }
        return strtoupper(md5($sign . "&key=" . $key));
    }

    /**
     * 数组转 xml
     * @param $arr
     * @return string
     * @author: gaolei 2021/4/24 12:04 下午
     */
    public function arrayToXml($arr): string
    {
        $xml = "<xml>";
        foreach ($arr as $key => $val) {
            if (is_numeric($val)) {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            } else {
                $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
            }
        }
        $xml .= "</xml>";
        return $xml;
    }

    /**
     * xml 数组
     * @param $xml
     * @return array|string[]
     * @author: gaolei 2021/4/27 12:29 下午
     */
    public function xmlToArray($xml): array
    {
        return array_map(static function ($v) {
            return (string)$v;
        }, (array)$xml);
    }

    public const CODE_SUCCESS = 200;
    public const CODE_FAILURE = 500;

    /**
     * 返回成功数据包
     * @param string $msg
     * @param array $data
     * @return array
     * @author: gaolei 2021/4/27 11:43 上午
     */
    protected function success(string $msg = '操作成功', $data = []): array
    {
        $code = self::CODE_SUCCESS;
        return compact('code', 'msg', 'data');
    }

    /**
     * 返回失败数据包
     * @param string $msg
     * @param array $data
     * @return array
     * @author: gaolei 2021/4/27 11:42 上午
     */
    protected function failure(string $msg = '操作失败', $data = []): array
    {
        $code = self::CODE_FAILURE;
        return compact('code', 'msg', 'data');
    }

    /**
     * 返回指定数据包
     * @param int $code
     * @param string $msg
     * @param array $data
     * @return array
     * @author: gaolei 2021/4/27 11:42 上午
     */
    protected function return(int $code, string $msg, $data = []): array
    {
        return compact('code', 'msg', 'data');
    }

    protected function getUserIp()
    {
        if (isset($_SERVER)) {
            if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
                $arr = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']);
                foreach ($arr as $ip) {
                    $ip = trim($ip);
                    if ($ip !== 'unknown') {
                        $realIp = $ip;
                        break;
                    }
                }
            } else if (isset($_SERVER['HTTP_CLIENT_IP'])) {
                $realIp = $_SERVER['HTTP_CLIENT_IP'];
            } else if (isset($_SERVER['REMOTE_ADDR'])) {
                $realIp = $_SERVER['REMOTE_ADDR'];
            } else {
                $realIp = '0.0.0.0';
            }
        } else if (getenv('HTTP_X_FORWARDED_FOR')) {
            $realIp = getenv('HTTP_X_FORWARDED_FOR');
        } else if (getenv('HTTP_CLIENT_IP')) {
            $realIp = getenv('HTTP_CLIENT_IP');
        } else {
            $realIp = getenv('REMOTE_ADDR');
        }
        preg_match('/[\\d\\.]{7,15}/', $realIp, $onlineip);
        return (!empty($onlineip[0]) ? $onlineip[0] : '0.0.0.0');
    }

    /**
     * 发起 GET 请求
     * @param string $url
     * @param array $options
     * @return bool|string
     */
    protected function curlGet(string $url = '', array $options = [])
    {
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        if (!empty($options)) {
            curl_setopt_array($ch, $options);
        }
        //https请求 不验证证书和host
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        $data = curl_exec($ch);
        curl_close($ch);
        return $data;
    }

    /**
     * 发起 POST 请求
     * @param string $url
     * @param string $postData
     * @param array $options
     * @return bool|string
     * @author: gaolei 2021/4/24 10:28 上午
     */
    protected function curlPost(string $url = '', string $postData = '', array $options = array())
    {
        if (is_array($postData)) {
            $postData = http_build_query($postData);
        }
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30); //设置cURL允许执行的最长秒数
        if (!empty($options)) {
            curl_setopt_array($ch, $options);
        }
        //https请求 不验证证书和host
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        $data = curl_exec($ch);
        curl_close($ch);
        return $data;
    }

}